Servlet本质
开发步骤
- 在webapps目录下新建一个目录:(webapp的根)
- 在webapp的根下新建一个目录:WEB-INF(Servlet规范,必须大写)
- 在WEB-INF目录下新建一个目录:classes(存放java编译后的class文件)
- 在WEB-INF目录下新建一个目录:lib(可以存放第三方的jar包)
- 在WEB-INF目录下新建一个目录:web.xml(必须存在,配置了请求路径和Servlet类之间的对照关系)
- 编写java小程序,实现Servlet接口(Tomcat服务器实现了Servlet规范,Servlet接口不在JDK当中,是Oracle提供的,是JavaEE规范中的一员)从JakartaEE9开始,Servlet接口的全名变为:jakarta.servlet.Servlet
Servlet规范
- 规范了哪些接口
- 规范了哪些类
- 规范了一个web应用中应该有哪些配置文件
- 规范了一个web应用中配置文件的名字
- 规范了一个web应用中配置文件存放的目录
- 规范了一个web应用中配置文件的内容
- 规范了一个合法有效的web应用他的目录结构应该是怎样的
- …
Servlet对象的生命周期
什么是Servlet对象的生命周期
* Servlet对象什么时候被创建
* Servlet对象什么时候被创建
* Servlet对象创建了几个
* Servlet对象的生命周期:Servlet对象从出生到死亡
Servlet对象是由谁来维护的
* Servlet对象的创建,对象上方法的调用,对象的销毁,Javaweb程序员是无法干涉的
* Servlet对象的生命周期是由Tomcat服务器(WEB Servlet:WEB容器)全权负责
* 自己创建的Servlet对象是不受WEB容器管理的
Servlet对象的创建
* 默认情况下,服务器在启动时Servlet并不会被实例化,当用户发送第一次请求时Servlet对象被创建(这个设计是合理的,如果提前创建会消耗内存,并且创建出来的Servlet一直不进行访问,就没有用处)
* Servlet对象被创建出来以后,Tomcat服务器马上调用Servlet对象的init()方法,然后马上调用service()方法
* 让服务器启动的时候创建Servlet对象,就必须添加0,标签中的整数越小,优先级越高,越早创建
* 用户再次请求时,Servlet对象不会新建,直接用创建好的Servlet对象调用service()方法
1.Servlet是单实例的,但Servlet类并不符合单例模式,是假单例(Tomcat只创建了一个,所以导致单例。真单例模式构造方法是私有化的)
2.无参数构造方法,init方法只在第一次用户发送请求的时候执行,也就是说无参构造只执行一次,init方法也只被Tomcat调用一次
* Servlet的无参构造器和init方法都是在第一次创建的时候被创建且调用一次,但并不可用无参构造代替init方法因为:Servlet规范中不建议手动编写构造方法,因为很容易让无参构造方法消失,可能会导致Servlet对象无法实例化,所以init存在是有必要的
Servlet对象的销毁
* Servlet的destroy方法制备Tomcat服务器调用一次
* 在服务器关闭的时候要销毁Servlet对象的内存,在销毁之前,Tomcat会自动调用Servlet对象的destroy方法
Servlet对象的使用
* init方法:通常做初始化操作,并且只需执行一次
* service方法:处理用户请求的核心方法
* destroy方法:进行资源的关闭,资源保存
存在问题
@Override
public void init(ServletConfig servletConfig) throws ServletException {}
@Override
public ServletConfig getServletConfig() {return null;}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {}
@Override
public String getServletInfo() {return null;}
@Override
public void destroy() {}
这五个方法在每次实现时都需要重写,但我们只需要service方法
——————————————————————————————————————————————
解决办法(GenericServlet抽象类,有一个抽象方法service)
- 实现Servlet接口,是一个适配器,以后的Servlet继承GenericServlet,只需重写service方法
public class ServletStart extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {}
}
- Tomcat服务器创建了ServletConfig对象,调用init方法,将ServletConfig对象传给init方法
public void init(ServletConfig config) throws ServletException {
this.config = config;
}
- 但是重写了init方法后config可能会为空
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
- 以后重写的都是无参的init方法
ServletConfig
- ServletConfig是一个接口,Servlet规范中的一员,Tomcat服务器实现了ServletConfig接口
- 一个Servlet对象只有一个ServletConfig对象,ServletConfig是Servlet对象的配置信息对象,一个Servlet对象就有一个配置信息对象
- ServletConfig对象中封装了标签中的配置信息
- ServletConfig接口中的方法
String getServletName();
ServletContext getServletContext();
String getInitParameter(String var1);
Enumeration<String> getInitParameterNames();
- 以上方法在Servlet类当中,都可以使用this调用,因为GenericServlet实现了ServletConfig接口
ServletContext(应用域)
- 一个Servlet对象对应一个ServletConfig,但在同一个webapp中,只要在同一个应用,所有的Servlet对象都共享同一个ServletContext对象
- ServletContext对象在服务期启动阶段创建,在服务器关闭的时候销毁,是应用级对象
- ServletContext对象被称为Servlet上下文对象(Servlet对象的四周环境对象)
- 一个ServletContext对象通常对应一个web.xml文件
- ServletContext是一个接口,Tomcat服务器对ServletContext接口进行实现
- ServletContext常用方法
String getInitParameter(String var1);//通过初始化参数的name获取value
Enumeration<String> getInitParameterNames();//获取初始化参数的name
String getContextPath();//动态获取应用的根路径
String getRealPath(String var1);//获取文件的绝对路径
- 如果所有的用户共享一份数据,并且这个数据很少被修改,数据量很少,可以放在ServletContext域中
1.不是共享的没有意义,只有共享的数据放进去才有意义
2.数据量太大的话,太占用堆内存,并且这个对象的生命周期比较长,服务器关闭时,对象才会被销毁,大量数据会影响服务器的性能
3.共享数据,如果涉及修改,必然会存在线程并发所带来的安全问题
PrintWriter out = servletResponse.getWriter();
out.print(servletConfig);//org.apache.catalina.core.StandardWrapperFacade@33914ac2
ServletContext servletContext = this.getServletContext();
out.print(servletContext);//org.apache.catalina.core.ApplicationContextFacade@3d56a2c0
在编写Servlet类的时候,实际上是不会直接继承GenericServlet的,基于HTTP传输协议,在Servlet规范中,提供了HttpServlet,我们编写的Servlet要继承HttpServlet
public interface Servlet(接口)
public abstract class GenericServlet implements Servlet(抽象类)
public abstract class HttpServlet extends GenericServlet(抽象类)
HTTP协议
- 协议:一套规范,就是一套标准
- HTTP协议:W3C(万维网联盟组织)制定的一种超文本传输协议(通信协议:发送消息的模板提前被创建好)
- 超文本:不是普通文本,比如:声音,视频,图片等
- 浏览器 —> WEB服务器:请求(request)
- WEB服务器 —> 浏览器:响应(response)
HTTP的请求协议(B–>S)
- 请求包括:请求行,请求头,空白行,请求体
- 请求行
1.第一部分:请求方式
get ,post ,delete ,put ,head ,options ,trace
2.第二部分:URI
URI:统一资源标识符。代表某个资源的名字,无法定位资源
URL:统一资源定位符。代表某个资源,可以定位资源(包括URI)
3.第三部分:HTTP协议版本号 - 请求头
请求的主机,主机的端口,浏览器信息,平台信息等 - 空白行:区分请求头与请求体
- 请求体:向服务器发送的具体数据
HTTP的响应协议(S–>B)
- 响应包括:状态行,响应头,空白行,响应体
- 状态行
1.第一部分:协议版本号(HTTP/1.1)
2.第二部分:状态码(不同的响应结果对应不同的码)
200:响应成功,正常结束
404:访问资源不存在,路径错误或者没有对应资源
405:前端发送的请求方式与后端请求处理的方式不一致
500:服务器端的错误
3.第三部分:状态的描述信息 - 响应头
响应的内容类型,内容长度,时间等 - 空白行:区分响应头与响应体
- 响应体:响应的正文,长字符串,会被浏览器渲染,解释并执行
发送请求
- 到目前为止,只有在form表单上设置method="post"时,才能发送post请求
- 在地址栏输入url,点击超链接,method=“get”…发送get请求
- get与post区别
get请求发送的数据会显示在浏览器上(get在请求头上发送数据)
post请求发送数据在请求体中发送,不会回显在浏览器的的地址栏是上
get只能发送普通的字符串,长度有限制,无法发送大数据量,比较适合从服务器端获取数据
post可以发送任何类型的数据,大数据量,适合向服务器获取数据
HttpServlet
- HttpServlet是专门为HTTP协议准备的
- HttpServlet对象中封装了:HttpServletRequest,HttpServletResponse(封装了请求协议中的全部内容)
- Tomcat服务器将请求协议中的数据全部解析出来,封装到request对象
WEB-INF:存放的资源是受保护的,不能在浏览器上通过路径直接访问
HttpServletRequest接口
- HttpServletRequest接口是Servlet规范中的一员
- HttpServletRequest接口的父接口:ServletRequest
public interface HttpServletRequest extends ServletRequest{}
- Tomcat服务器实现了HttpServletRequest接口,封装了HTTP的请求协议
- request对象只在当前请求中有效,一次请求对应一个request
- 常用方法
String getParameter(String var1);//获取这个一维数组的第一个元素
Enumeration<String> getParameterNames();//获取Map集合中的所有Key
String[] getParameterValues(String var1);//根据key获取Map集合中的value
Map<String, String[]> getParameterMap();//获取Map
两个Servlet共享数据
- 将数据放到ServletContext应用域当中,但是范围太大,占用资源太多,不建议
- 将数据放到request域当中,使用转发(转发的下一个资源不一定是Servlet,只要是合法资源,都可以跳转)
- 转发时不加项目名,以"/"开始
String getParameter(String var1);//获取用户在浏览器上提交的数据
Object getAttribute(String var1);//获取请求域当中绑定的数据
req.getRemoteAddr();//获取客户端IP地址
req.setCharacterEncoding("UTF-8");//设置字符集
req.getContextPath();//获取应用的根路径
req.getMethod();//获取请求方式
req.getServletPath();//获取Servlet路径
资源跳转
转发 ,重定向
- 转发(一次请求)
req.getRequestDispatcher(req.getServletPath()).forward(req,resp);
//转发是一次请求,都在同一个request当中
//调用forward方法的时候,会将当前的request和response对象传递给下一个Servlet
- 重定向(两次请求)
resp.sendRedirect(req.getContextPath()+req.getServletPath());
//请求路径要添加项目名,浏览器会自发地向服务器发送一次全新的请求
- 本质区别
1.转发:由WEB服务器控制,跳转由Tomcat服务器内部完成
2.重定向:浏览器完成 - 如果Servlet当中向request域当中绑定了数据,希望从下一个Servlet中把request域里面的数据取出来,使用转发,其余使用重定向