Servlet 介绍
问题:
服务器在接收到浏览器的请求后,会自动调用对应的逻辑代码进行请求处理。但是逻辑代码是由程序员编写并放到服务器中,那么服务器怎么知道该怎么调用并调用哪个类和哪个方法来进行请求处理。
解决:
程序员在编写代码的时候如果能够按照服务器能够识别的规则进行编写, 浏览器按照指定的规则进行发送请求,那么服务器就可以调用并执行响应的逻辑代码进行请求处理了。
实现:
Servlet 技术
概念:
狭义的 Servlet 是指 Java 语言实现的一个接口,广义的 Servlet 是指任何实现了这个 Servlet 接口的类,一般情况下,人们将 Servlet 理解为后者。Servlet 运行于支持 Java 的应用服务器中。从原理上讲,Servlet 可以响应任何类型的请求,但绝大多数情况下 Servlet 只用来扩展基于 HTTP 协议的 Web 服务器
请求 ---> Tomcat ---> Servlet(封装的类)--响应输出txt/html/json
特点:
运行在支持 java 的应用服务器上
Servlet 的实现遵循了服务器能够识别的规则,也就是服务器会自动的根据请求调用对应的 servlet 进行请求处理。
简单方便,可移植性强
使用:
1、创建普通的 java 类并继承 HttpServlet
2、覆写 service 方法
3、在 service 方法中书写逻辑代码即可
运行流程:
URL组成:
服务器地址:端口号/虚拟项目名 /servlet注解的路径(配置的路径)
URI:虚拟项目名 /servlet 的别名
浏览器发送请求到服务器,服务器根据请求 URL 地址中的 URI 信息在 webapps 目录下找到对应的项目文件夹,然后在 web.xml 中检索对应的 servlet,找到后调用并执行 Servlet。
DoGet方法用于GET请求
DoPost方法用于POST请求
通过对 Servlet 的调用流程学习,我们知道 web.xml 文件的配置是为了保护servlet。其实服务器应该调用哪个 servlet 进行请求的处理, 在浏览器的请求地址中写的很清楚。
注解配置:
1、精确匹配,一般作用于站点独特的几个路径,首页、登录、注册等等
@WebServlet("/hello") |
2、路径匹配,一般用于产品页,新闻页面,百科页面一般用于大量相类似的页面
@WebServlet("/product/*") |
3、扩展名匹配
@WebServlet("*.json") |
匹配多个路径:
@WebServlet(urlPatterns= {"/morepath","*.do","/more/*"}) |
package cn.sxt; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class lianxi */ @WebServlet(urlPatterns= {"/morepath","*.do","/more/*"}) public class lianxi extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public lianxi() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); response.getWriter().append("今天:").append(request.getContextPath()); response.getWriter().append("Served at: ").append(request.getContextPath()); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }
Servlet的web.xml 配置:
Web.xml 配置的作用:保护Servlet。(现在匹配一般都没用xml了,使用的是上面的@,简单方便)
配置方式一:精确匹配
<!-- 配置方式一 --> <servlet> <servlet-name>my3</servlet-name> <servlet- class>com.bjsxt.servlet.MyServlet3</servlet-class> </servlet> <servlet-mapping> <servlet-name>my3</servlet-name> <url-pattern>/my3</url-pattern> </servlet-mapping> |
配置方式二:路径匹配
<servlet> <servlet-name>my3</servlet-name> <servlet- class>com.bjsxt.servlet.MyServlet3</servlet-class> </servlet> <servlet-mapping> <servlet-name>my3</servlet-name> <url-pattern>/news/*</url-pattern> </servlet-mapping> |
配置方式三:扩展名匹配
<servlet> <servlet-name>my3</servlet-name> <servlet- class>com.bjsxt.servlet.MyServlet3</servlet-class> </servlet> <servlet-mapping> <servlet-name>my3</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> |
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>13-1-servlet_path</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>my3</servlet-name> <servlet-class>cn.sxt.test.XmlConfig</servlet-class> </servlet> <servlet-mapping> <servlet-name>my3</servlet-name> <url-pattern>/my3</url-pattern> <url-pattern>/my/*</url-pattern> <url-pattern>*.my</url-pattern> </servlet-mapping> </web-app>
加载时机:
服务器启动的时候会将 webapps 中部署好的项目统一进行加载,并完成对每个项目的 web.xml 文件的加载。
注意:
一个 Servlet 可有拥有多个 url-pattern 配置,但是一个url-pattern 配置只能对应一个Servlet
路径和扩展名匹配无法同时设置,比如下面的三个<url-pattern>都是非法的,如果设置,启动tomcat服务器会报错。
<url-pattern>/kata/*.jsp</url-pattern>
<url-pattern>/*.jsp</url-pattern>
<url-pattern>he*.jsp</url-pattern>
另外注意:<url-pattern>/aa/*/bb</url-pattern>
这个是精确匹配,url必须是 /aa/*/bb,这里的*不是通配的含义
优先顺序
当一个url与多个servlet的匹配规则可以匹配时,则按照 “ 精确路径 > 最长路径>扩展名”这样的优先级匹配到对应的servlet。举例如下:
例1: servletA 的url-pattern为 /test, servletB的url-pattern为 /* ,这个时候,如果我访问的url为http://localhost/test ,这个时候容器就会先进行精确路径匹配,发现/test正好被servletA精确匹配,那么就去调用servletA,不会去管servletB。 例2: servletA的url-pattern为/test/*, servletB的url-pattern为/test/a/*,此时访问http://localhost/test/a时,容器会选择路径最长的servlet来匹配,也就是这里的servletB。 例3: 比如 servletA的url-pattern:*.action , servletB的url-pattern为 /* ,这个时候,如果我访问的url为http://localhost/test.action,这个时候容器就会优先进行路径匹配,而不是去匹配扩展名,这样就去调用servletB。 |
Servlet 生命周期
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
Servlet 通过调用 init () 方法进行初始化。 Servlet 调用 service() 方法来处理客户端的请求。 Servlet 通过调用 destroy() 方法终止(结束)。 |
最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
现在让我们详细讨论生命周期的方法。
init() 方法
init 方法被设计成只调用一次。它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用。因此,它是用于一次性初始化,就像 Applet 的 init 方法一样。
Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,但是您也可以指定 Servlet 在服务器第一次启动时被加载。
当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。
init 方法的定义如下:
public void init() throws ServletException { // 初始化代码... } |
service() 方法
service() 方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。
每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。
下面是该方法的特征:
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException{ } |
service() 方法由容器调用,service 方法在适当的时候调用 doGet、doPost、doPut、doDelete 等方法。所以,您不用对 service() 方法做任何动作,您只需要根据来自客户端的请求类型来重写 doGet() 或 doPost() 即可。
doGet() 和 doPost() 方法是每次服务请求中最常用的方法。下面是这两种方法的特征。
doGet() 方法
GET 请求来自于一个 URL 的正常请求,或者来自于一个未指定 METHOD 的 HTML 表单,它由 doGet() 方法处理。
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Servlet 代码 } |
doPost() 方法
POST 请求来自于一个特别指定了 METHOD 为 POST 的 HTML 表单,它由 doPost() 方法处理。
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Servlet 代码 } |
destroy() 方法
destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。
在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。destroy 方法定义如下所示:
public void destroy() { // 终止化代码... } |
架构图
下图显示了一个典型的 Servlet 生命周期方案。
第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。
Servlet 容器在调用 service() 方法之前加载 Servlet。
然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。
package cn.sxt; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class lianxi */ @WebServlet("/lianxi") public class lianxi extends HttpServlet { private static final long serialVersionUID = 1L; private String abc=""; /** * @see HttpServlet#HttpServlet() */ public lianxi() { super(); // TODO Auto-generated constructor stub } @Override public void init() throws ServletException { // TODO Auto-generated method stub super.init(); System.out.println("start init"); abc= "helloworld_abc"; }
@Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub super.service(req, resp); System.out.println("service....."); if(req.getMethod().equals("GET")) { doGet(req, resp); }else { doPost(req, resp); } }
/** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.getWriter().append("Served at: ").append(request.getContextPath()); response.getWriter().println(" "+abc); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } @Override public void destroy() { // TODO Auto-generated method stub super.destroy(); System.out.println("destroy"); } }