@TOC
前言
动态web的核心是Servlet,由tomcat解析并执行,本质是Java中的一个类(面向对象)这个类的功能十分强大几乎可以完成全部功能,在Java规范中只有Servlet实现类实例化的对象才能被浏览器访问,所以掌握Servlet具有重要意义!
一.导入方式
由于jdk中没有servlet对应的jar包,所以需要咱们手动引入,有两种方式:
1.可以采取向lib目录导入servlet-api的jar包的方式
2.在maven项目中设置如下坐标,并添加相关依赖到依赖库中即可(推荐使用这种,在maven里选择webapp的骨架建立项目会自动给你配置好web.xml文件)
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
版本号可以自己定,依赖范围要配置成provided,否则会和其他jar包冲突
二.Servlet生命周期(🏳️🌈)
原生的Servlet项目都是实现Servlet接口,功能都是通过实现这个接口或者继承HttpServlet来完成的,其实在IDEA里重写方法的过程中所对应的顺序就是他的生命周期,以下面为例:
按照每一个方法翻译而来的字面意思,流程是:
初始化——得到服务配置——服务——获取服务信息——销毁,简言之,就是一个从初始化到服务再到消亡的过程。
初始化阶段:public void init(ServletConfig servletConfig)
当服务器启动,读取web.xml文件的过程中,Tomcat加载 Servlet,加载完成后,Servlet 容器会创建一个 Servlet 实例 并调用 init()方法,init()方法只会调用一次,这个没什么好解析的,就是面向对象中类特性的体现
服务阶段:public void service(ServletRequest servletRequest, ServletResponse servletResponse)
这个方法的形参里有两个ServletRequest和ServletResponse类型的接口,翻译过来就是服务请求、服务响应,Tomcat启动时自动装载某些 servlet,并在 Servlet 容器启动后,浏览器首次向 Servlet 发送请求,发送的请求和响应作为参数就传到了service方法对应的形参里进行处理。看了一下jdk的源码,发现两个接口下面都有很多的抽象方法,至于请求和响应在底层是怎样执行的源码里啥都没写,目前还不知道(推测是个底层驱动)
消亡阶段:public void destroy()
从图中规定的顺序不难看出,执行到最后的方法也就预示着Servlet的生命即将结束
在JDK的源码中,Servlet接口下的destory()没有方法体,应该也是和启动线程的start0()方法类似被开发者封装简化了
完整流程演示:
@WebServlet("/demo1")
public class SevDemo1 implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {System.out.println("我在初始化~~~");}
@Override
public ServletConfig getServletConfig() {return null;}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("hello world!!!!");}
@Override
public String getServletInfo() {return null;}
@Override
public void destroy() {System.out.println("我走了,拜拜~~~");}
}
控制台打印的信息很好地反映了执行情况:
至于public ServletConfig getServletConfig()
和public String getServletInfo()
在实现接口后重写的方法中默认返回的是null,应该是两个起补充作用的方法
三.继承HttpServlet
在实际开发中采用继承HttpServlet类的方式开发Servlet程序更加方便,因为实现接口重写那麽多方法是真的麻烦,而通过继承的方式就可以根据需要选择性的重写doGe()或doPost()方法就简单很多,比如
public class HttpDemo 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()...");
}
}
至于方法体里写什么内容就要看对应的业务场景了
气氛烘托到这里了就不得不说一下GET和POST的区别了
GET&POST(🏳️🌈)
以前老师是教我这样理解的——我把一封信放在信封里邮寄出去,我可以选择密封或者不密封,而这就会导致信的内容会不会被别人看到,若是前者则对应POST,后者就对应GET
当然,这只是抽象层面,而从具体方面来看:
==1.从功能上来讲==,get是从服务器上获取数据,post是向服务器传送数据
==2.从报文上来讲==,在不带参数时区别就单纯是第一行方法名不同,而在带参数时GET方法的参数放在请求头URL中,POST方法的参数放在请求体BODY中 注:GET方法的参数写在?后,用&分割
==3.从安全性来讲==,其实他们都不安全,因为http是明文传输(在网页按F12进入开发者模式发现两种方式都能看到数据信息)。但是这张图应该很生动形象也能反映一些问题,相比较之下POST还是比GET安全,因为数据在地址栏不可见,哈哈哈
四.Servlet相关性质(八股文)
1.Servlet 是一个供其他 Java 程序(Servlet 引擎)调用的 Java 类,不能独立运行
2.对于每次访问请求,Servlet 引擎都会创建一个新的 HttpServletRequest 请求对象和一个 新的 HttpServletResponse 响应对象,然后将这两个对象作为参数传递给它调用的 Servlet 的 service()方法,service 方法再根据请求方式分别调用 doXXX 方法
3.针对浏览器的多次 Servlet 请求,通常情况下,服务器只会创建一个 Servlet 实例对象, 也就是说 Servlet 实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至 web 容器退出/或者 redeploy 该 web 应用,servlet 实例对象才会销毁
4.如果在<servlet>元素中配置了一个<load-on-startup>元素,那么 WEB 应用程序在启动时, 就会装载并创建 Servlet 的实例对象、以及调用 Servlet 实例对象的 init()方法
5.在 Servlet 的整个生命周期内,init 方法只被调用一次。而对每次请求都导致 Servlet 引 擎调用一次 servlet 的 service 方法
——ps:刷dy整理出来的
五.Request&Response
对于这些内部方法来说我觉得会用API就行
1.HttpServletRequest
HttpServletRequest 表示请求过来的信息:
公共接口类HttpServletRequest继承自ServletRequest。客户端浏览器发出的请求被封装成为一个HttpServletRequest对象。对象包含了客户端请求信息包括请求的地址,请求的参数,提交的数据,上传的文件客户端的ip甚至客户端操作系统都包含在其内。
还是面向对象那一套,封装成类后调用里面的方法,部分常用方法如下:
public String getAuthType() | 返回这个请求的身份验证模式 |
---|---|
public Cookie[ ] getCookies() | 返回一个数组,该数组包含这个请求中当前的所有cookie |
public long getDateHeader(String name) | 返回指定的请求头域的值,这个值被转换成一个精确到毫秒的长整数 |
public String getHeader(String name) | 返回一个请求头域的值。(译者注:与上一个方法不同的是,该方法返回一个字符串) |
2.HttpServletResponse
HttpServletResponse 表示所有响应的信息,需要设置返回给客户端的信息,通过 HttpServletResponse 对象来进行设置即可,会用几个核心API就够了
addHeader(String name,String value) | 将指定的名字和值加入到响应的头信息中 |
---|---|
encodeURL(String url) | 编码指定的URL |
setStatus(int sc) | 给当前响应设置状态码 |
setHeader(String name,String value) | 将给出的名字和值设置响应的头部 |
六.请求转发模型(🏳️🌈)
先前在网页中输出hello java!只是一次请求对应一个Servlet,浏览器——Tomcat——Servlet没有实现请求的转发,而在真实环境中网站不可能只进行一次交互,往往需要在一次请求中使用到多个servlet完成
1.一个 web 资源收到客户端请求后,通知服务器去调用另外 一个 web 资源进行处理
- HttpServletRequest 对象(也叫 Request 对象)提供了一个 getRequestDispatcher 方法,该 方法返回一个 RequestDispatcher 对象,调用这个对象的 forward 方法可以实现请求转发
- request 对象同时也是一个域对象,开发人员通过 request 对象在实现转发时,把数据 通过 request 对象带给其它 web 资源处理
在实际场景中,用户输入信息提交后得到反馈这一过程就是典型的请求转发,就像这样:
第一个Servlet里的情况
@WebServlet("/demo2")
public class Sevdemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("这里是demo2~~");
//存储数据
req.setAttribute("懒羊羊","你好!");
//请求转发
req.getRequestDispatcher("/demo3").forward(req,resp);
}
}
第二个Servlet里的情况
@WebServlet("/demo3")
public class Sevdemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("这里是demo3~~");
Object msg= req.getAttribute("懒羊羊");
System.out.println(msg);
}
}
当我启动Tomcat来访问demo2时:
实现了请求的转发!
既然是一个Servlet转发给另一个Servlet,且是部署在同一个Tomcat中,那就说明不能访问当前web工程外的资源、同一次 HTTP 请求中,进行多次转发,仍然是一次 HTTP 请求
七.请求重定向
和请求转发比较类似,请求重定向指:一个 web 资源收到客户端请求后,通知客户端去访问另外一个 web 资源,这称之为请求重定向,还是通过API调方法来实现,基本流程如下:
首先通过setStatus()设置响应状态码,然后setHeader("location","http://www.taobao.com")设置新地址
就实现了请求重定向
@WebServlet("/demo2")
public class Sevdemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("这里是demo2~~");
//设置响应状态码
resp.setStatus(302);
//设置新地址
resp.setHeader("location","http://www.taobao.com")
}
}
还有第二种方法,其实和这也大同小异
到这里动态web的核心Servlet就介绍完了
内容以及配图都是作者原创,若是觉得不错的话可以三连一下,懒羊羊蟹蟹你~