JavaEE day3:Servlet
为什么要用Servlet?
因为企业级应用工作时,需要实现以下三步
- 和客户端建立tcp连接
- 解析http请求报文(真正拿到客户端发送的数据)
- 实现产品的业务逻辑
而每个应用都实现第一、第二步的话效率很低
那么我们需要引入一个集成1、2步的服务器程序Servlet
此时我们就可以自己写程序实现自己的产品的业务逻辑
client发出http请求报文——client和tomcat建立tco连接——tomcat解析http请求报文——并且应用拿到解析好的http请求——应用根据业务逻辑来处理请求-tomcat将应用处理的结果封装到http响应报文——Tomcat将响应报文发送给客户端
- 那么我们如何拿到tomcat帮助我们解析好的http请求
- tomcat就是把请求报文转化成第一个表示http请求的对象
public abstract void service (ServletRequest req.ServletResponse res)throws ServletException,java.io.IOException
Servlet简介
- Servlet是一门用于开发动态web资源(Servlet根据不同的请求产生不同的响应的)的技术
使用javac来编译java程序
-如果还是用的是之前的jdk的版本会无法找到Servlet类
- 此时要将tomcat的lib目录里的Servlet-api导入jdk运行环境中(jdk1.8-jre-lib-ext)
实现Servlet
- 编写一个java类,实现Servlet接口
- 把开发好的java类部署到web服务器中
- 将Servlet编译之后生成的字节码文件放到应用的web-inf目录下的classes目录中
- (解决的核心问题是,让tomcat找到合适的Servlet,将请求交给专们用来处理这个请求的Servlet)
通过WEB-INF里的web.xml里的Servlet和Servlet-mapping,告诉tomcat哪个Servlet处理哪种请求
- Servlet /servlet作了映射:将Servlet的字节码的全类名,映射到一个名称,就是给字节码对应的Servlet起了个名字
- servlet-maping /servlet-maping 将一个url映射到Servlet的名称
- 这样就可以通过url访问Servlet的名称,在通过Servlet的名称访问 class文件(这里比较绕)
- 如果想输出到客户端,需要使用ServletResponse res调用getWriter().println();
- 通过形参中的req拿到请求,res将处理结果给到客户端
Servlet生命周期
创建—调用—销毁
- 懒加载:我们定义的MyFirstServlet什么时候被实例化呢?第一次被请求的时候,这样做的好处(壁纸与气动tomcat就实例化MyFirstServlet),其实是对资源利用的一种优化。
- 什么时候执行service方法(执行业务逻辑呢?)http请求一次,处理一次
- 什么时候被销毁呢?应用退出,被undeploy(和部署web应用相反),redeloy=先undeloy再deploy
- 客户端发出请求http://localhost:8080/MyFirstServlet/haha,服务器根据web.xml文件的配置,找到url-pattern子元素的值“haha”的servlet-mapping元素
- 读取servlet-mapping元素的servlet-name子元素的值,由此确定Servlet的名字为”haha”
- 找到servlet-name值为haha的servlet元素,其类名为servletA
- 读取servlet元素的servlet-class子元素的值,由此确定Servlet的类名(全类名)为bamzhy.MyFirstServlet.servletA。
- 到Tomcat安装目录/webapps/app/WEB-INF/classes/bamzhy/MyFirstServlet目录下查找到servletA.class文件
- 初始化,并执行这个类的 service方法。
Servlet的运行过程
Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
- Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
装载并创建该Servlet的一个实例对象。
- 调用Servlet实例对象的init()方法。
- 创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
- WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
Servlet的一些细节
- doPost方法专门用来处理post提交的请求
- doGet方法专门用来处理get提交的请求
- 这两种方法必须被overide
-
值得一提的时候,我由于在注解中的urlpattern里边忘记前置“/”导致了Servlet没有部署 成功
- 同时,同一个Servlet可以由多个urlpattern映射;
在Servlet映射到的URL中也可以使用 ” * ” 通配符,但是只能有两种固定的格式:
一种格式是“*.扩展名”,
一种格式是以正斜杠(/)开头并以“/*”结尾。对于如下的一些映射关系:
Servlet1 映射到 /abc/*
Servlet2 映射到 /*
Servlet3 映射到 /abc
Servlet4 映射到 *.html如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就会成为当前web应用程序的缺省Servlet
- 凡是在web.xml文件中找不到匹配的servlet-mapping元素的url,它们的访问请求都将交给缺省Servlet处理。
- 在
关于匹配方面的结论:
- 可以精确匹配,就用最精确的匹配
- /的优先级要高于.html
如何为Servlet配置启动时装载
- 在Servlet元素汇总配置一个load-on-startup元素,那么web应用程序在启动时,就会装载并创建Servlet的实例对象以及调用Servlet实例对象的init方法
- 可以使得当前Servlet配置为启动时装载,为整个web应用创建必要的数据库表和数据
ServletConfig对象
- 在Servlet的配置文件中,可以使用一个或多个init-param标签为 某个servlet配置一些初始化参数。
- 阅读ServletConfig API,并举例说明该对象的作用:
获得字符集编码
获得数据库连接信息
ServletContext对象
servletContext=一个web应用
- WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
- 由于一个web应用中的所有Servlet共享同一个ServletContext对象,因此Servlet可以通过ServletContext对象来实现通讯
- ServletContext对象通常也被称之为context域对象(整个web应用)
ServletContext的应用
- 获取web应用的初始化参数(多个Servlet获取相同参数)
- 多个Servlet通过ServletContext对象实现数据共享
- 实现Servlet的转发(request)
几个疑难问题
我们配置的默认Servlet是否会真正覆盖tomcat的默认的Servlet?
- tomcat在接收请求之后,首先会将url中拿到的url-pattern去和url指明的应用中匹配urlpattern,如果在已经配置了应用的默认Servlet的前提下,在访问tomcat中不存在的应用(不是当前应用时),tomcat的默认Servlet会接收请求并且处理。所以我们应用的默认Servlet并未真正覆盖tomcat的默认的Servlet。
/* 和/ 有没有优先级之分?
- /* 要比/优先级高
正确获取资源的绝对路径
- ServletContext的getRealPath方法能够帮助我们获取正确的绝对路径