1.Servelt本质
sun公司制定的一套web开发规范,web服务器厂商和Java开发人员共同遵守的一套接口,大多数时候Java开发人员是Servlet接口的实现者,web服务器(tomcat)是Servlet接口的调用者.启动服务器,其实就相当于启动main方法,然后服务器自动调用Java开发人员写的实现类,执行程序.因为Servlet规范的存在,不管是tomcat,jboss还是其他服务器,只要程序员按照Servlet规范写的代码,服务器都能自动调用运行.
2.Servlet接口方法
- public void init(ServletConfig servletConfig)
- public void service(ServletRequest req,ServletResponse response)
- public ServletConfig getServletConfig()
- public String getServletInfo()
- public void destroy()
3.Servlet的生命周期
默认情况下,服务器启动的时候不会创建Servlet对象,只要用户第一次发起请求,涉及到对应的Servlet,这时候才开始创建Servlet对象,对象创建好后tomcat服务器会按顺序自动调用init方法,service方法,当Servlet对象即将销毁之前会调用destroy方法
特别注意:Servelt对象是tomcat自动创建的,服务器中会维护一个map集合,key是路径,value就是Servlet对象.当然,若程序员手动去new的Servlet对象是不受tomcat管理的.对象在tomcat中是单例存在的,Servelt对象创建后,第二次,第三次访问,每访问一次,就调用一次service方法,init和destroy方法都只会执行一次,init方法是在Servlet的无参构造方法中调用了一次,因此若Servlet没有无参构造方法,会报错.
4.一个Servlet类的开发流程
- 自定义一个类实现Servlet接口
- 实现Servlet接口的所有方法: init,service,getServletConfig,getServletInfo,destroy等5个方法,在service方法中编写业务逻辑
- 在webap/WEB-INF/web.xml中编写
标签,绑定Servlet类和请求路径的关系,或者在类中通过标注@WebServlet() - 部署项目到服务器,启动tomcat
- 用户通过浏览器输入地址进行访问对应的Servlet
5.实现Servelt接口的缺点
- 每次都要实现init,destroy,getServletConfig,getServletInfo方法,但其实这些方法未必用得上,代码比较丑陋,不优雅
- 解决办法:实现GenericServlet抽象类
6.实现GenericServlet抽象类
- GenericServlet抽象类实现了Servlet,ServletConfig,Serializable三个接口
- 重写了Servlet接口的init,getServletConfig,getServletInfo和destroy方法
- 重写了ServletConfig接口的getServletName,getInitParameter,getInitParameterNames,getServletContext等方法
- 说白了是Servlet的儿子,类继承GenericServlet只用重写service方法,可谓变优雅了.
7.ServletConfig接口
- 首先,ServletConfig是一个接口,被GenericServlet抽象类继承,Servlet接口中有getServletConfig方法
- 默认情况下,ServletConfig对象是用户第一次发送请求,需要执行对应的Servlet类时由Tomcat创建,Servlet中的init方法需要传递ServletConfig对象,所以init方法肯定在SevletConfig对象创建之后执行.
- ServletConfig其实就是一个Servlet配置对象,封装了某个Servlet全部个人信息,包括Servlet名字,初始化参数名,初始化参数值,和上下文对象ServletContext
- 一个Servlet对应一个ServletConfig对象,100个Servlet对应100个ServletConfig对象,一个Servlet就对应一个web.xml中Servlet标签,里面的内容它都能获取到
- 接口有4个方法:gtInitParameter,getInitParamterNames,getServletName,getServletContext
8.ServletContext接口
- ServletContext是一个接口,一个webapp只有一个ServletContext对象,是一个应用上下文对象,一个web应用的大环境.
- tomcat中webapps目录下可以放多个webapp,即服务器下可以放多个应用,每个webapp只有一个web.xml配置文件,一个web.xml对应一个ServletContext对象,就像一个servlet标签对应一个ServletConfig对象.ServletContext又叫‘应用域’
- ServletContext对象在服务器启动时由服务器创建,在服务器关闭时销毁,对象存活周期比较长,应用中所有Servlet共享一个ServletContext对象
- ServletContext对象可以存放少量,共享,很少修改的数据.少量是因为堆内存有限,而ServletContext对象存活时间长,数据量太大占用内存大,影响性能;修改少是应为共享的数据如果进行修改必然存在线程安全问题;共享是因为ServletContext整个应用就一个,大家都有.
void setAttribute(String key,Object obj)
Object getAttribute(String key)
void removeAttribute(String key)
String getRealPath(String str)
String getContextPath()
Enumeration<Servlet> getServlets()
Enumeration<String> getServletNames()
String getInitParameter(String key)
Enumberation<String> getInitParameterNames()
Enumberation<String> getServletNames()
9.ServletRequest接口方法
Object getAttribute(String var1);//根据key获取请求域中的value
Enumeration<String> getAttributeNames();//获取请求域中所有key
String getCharacterEncoding();//获取请求的字符编码方式
void setCharacterEncoding(String var1) throws UnsupportedEncodingException;//设置请求编码方式
String getContentType();//获取内容类型
String getParameter(String var1);//根据参数名获得参数值
Enumeration<String> getParameterNames();//获取所有参数名
String[] getParameterValues(String var1);//得到所有参数值
Map<String, String[]> getParameterMap();//获取所有参数的key和value的map集合
void setAttribute(String var1, Object var2);//在请求域中放置值
void removeAttribute(String var1);//在请求域中删除值
RequestDispatcher getRequestDispatcher(String var1);//获取请求转发对象
ServletContext getServletContext();//获取应用域对象
10.ServletResponse接口方法
String getCharacterEncoding();//获取响应字符编码
String getContentType();//获取响应内容类型
PrintWriter getWriter() throws IOException;//获取输出对象
void setCharacterEncoding(String var1);//设置响应字符编码
ServletOutputStream getOutputStream() throws IOException;//得到输出流
11.HttpServlet抽象类
HttpServlet抽象类继承了GenericServlet抽象类,是一个专门适配http协议的类,比GenericServlet抽象类更适合在http协议下开发
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(HttpServletRequest req, HttpServletResponse resp)
// doPost(HttpServletRequest req, HttpServletResponse resp)
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
this.service(HttpServletRequest req, HttpServletResponse resp)
}
从HttpServlet方法中可以看出,HttpServlet类重写了GenericServlet的service(ServletRequest req,ServletResponse resp)方法,这个方法是只要有请求访问Servlet就会执行的,而service方法中调用了重载的service(HttpServletRequest req,HttpServletResponse resp)方法,而重载的service方法中对请求进行了判断,判断是post请求就执行doPost方法,是get请求就执行doGet方法,是put请求就执行doPut方法…但是值得注意的是,不管是doPost,doGet,HttpServlet中的实现都是报405错误,因为若是会执行父类的doGet方法,说明子类中的doGet方法没有执行,或者没有重写父类的doGet,只要重写对了,那执行子类的,这样就不会报错,这是应用了设计模式中的模板方法.
12.HttpServletRequest接口
继承了ServletRequest接口,具体方法如下
Cookie[] getCookies();//获取cookies
String getMethod();//获取请求方法类型
String getContextPath();//得到项目路径
String getRequestedSessionId();//得到请求的sessionid
String getRequestURI();//得到请求的uri
StringBuffer getRequestURL();//得到请求的url
String getServletPath();//得到servlet的地址
HttpSession getSession(boolean var1);//得到session
HttpSession getSession();//得到session
Object getAttribute(String var1);//根据key获取请求域中的value
Enumeration<String> getAttributeNames();//获取请求域中所有key
String getCharacterEncoding();//获取请求的字符编码方式
void setCharacterEncoding(String var1) throws UnsupportedEncodingException;//设置请求编码方式
String getContentType();//获取内容类型
String getParameter(String var1);//根据参数名获得参数值
Enumeration<String> getParameterNames();//获取所有参数名
String[] getParameterValues(String var1);//得到所有参数值
Map<String, String[]> getParameterMap();//获取所有参数的key和value的map集合
void setAttribute(String var1, Object var2);//在请求域中放置值
void removeAttribute(String var1);//在请求域中删除值
RequestDispatcher getRequestDispatcher(String var1);//获取请求转发对象
ServletContext getServletContext();//获取应用域对象
13.HttpServletResponse接口
继承ServletResponse
void addCookie(Cookie var1);
String getCharacterEncoding();//获取响应字符编码
String getContentType();//获取响应内容类型
PrintWriter getWriter() throws IOException;//获取输出对象
void setCharacterEncoding(String var1);//设置响应字符编码
ServletOutputStream getOutputStream() throws IOException;//得到输出流
void sendRedirect(String str);
14.资源跳转的两种方式:转发和重定向
转发:request.getRequestDispatcher("/user/list").forward(request,response)
转发是Servlet内部在服务器端自动完成的,从AServlet跳到BServlet,全程就是靠服务器自动完成,不涉及到浏览器,整个过程浏览器地址不会有变化,还是AServlet的访问地址,同时因为AServlet的request和response对象都传给了下一位BServlet,所以他们共享一个request域,数据可以得到共享.
重定向:response.sendRedirect(/blog/user/list)
重定向是response对象的方法,执行重定向方法后,服务器会把需要跳转的地址响应给浏览器,浏览器拿到地址后重新发送一个全新的请求,请求地址就是重定向穿过来的地址,这时候地址栏的地址就会实时变化,前后两个请求之间没有任何关系,不是同一个request域,自然无法在request域中共享数据.
举一个借钱的通俗例子:
转发: 张三找李四借钱,李四很仗义,自己没钱但是也没拒接,偷偷找王五借钱,借到的钱给了张三.对于张三而言,它认为钱是李四的,并不知道王五这个人.对应的转发也是一样的,浏览器的请求是访问AServlet拿到数据A,但是AServlet提供不了数据A,它通过转发跳转到BServlet拿到数据A,接着在浏览器上响应A.整个过程中浏览器始终以为自己只访问了AServlet,地址栏的地址也是指向AServlet,殊不知,AServlet内部访问BServlet.对于浏览器而言,这就是1次请求.
重定向:张三找李四借钱,李四直接了当说自己没钱,并告诉张三王五有钱,并贴心的给了王五的地址,让张三自己按照地址找王五借钱.张三得到王五地址后,就按照地址找到王五,并成功借到了钱.对于张三而言整个借钱的流程中,张三向李四借过钱,张三向王五借过钱,借了两次钱才成功.对应到Servlet中,浏览器先发起请求到AServlet,要求得到数据A,但是AServlet提供不了数据A,但是他知道BServlet可以得到数据A,它这人也诚实,老老实实告诉浏览器我不行,但是贴心的向浏览器返回了BServlet的请求地址,浏览器得到BServlet请求地址后就重新发起了一个全新的请求,请求指向BServlet.整个过程浏览器发送了2次请求,最终浏览器的地址定格在访问BServlet的地址.
重定向和转发的选择
如果AServlet在request域中绑定了数据,希望在BServlet中取出来并加工,则用转发,其他情况均用重定向.总之,两个Servlet涉及到request域中共享数据用转发,其他均用重定向,转发会用浏览器刷新问题,能用重定向的一定用重定向
15.session机制
session是维护浏览器和服务器的之间关联的一种技术.底层是使用cookie对象来实现的
session生命周期
- 创建: 当程序第一次执行request.getSession()时,服务器会自动创建session对象,并生成JSESSIONID,服务器会自动以key,value的形式,通过cookie对象(key:JSESSIONID,value:9384934938GGFA)返回给浏览器,浏览器保存cookie.
- 以后每次发送请求,浏览器都会以cookie形式携带上JESSIONID到服务器.服务器 可以根据JESSIONID在堆中找到对应的session对象.
- 销毁:分为手动销毁和自然销毁.手动销毁是指调用session.invalidate(),自然销毁指默认情况下session过30分钟会自然销毁,这个时间可以自己设置.
- 常用session机制,在用户登录成功后,把用户对象存放到session会话域中,只要session中存在用户,则用户是登录状态.当session对象失效了,自然用户就不处于登录状态了.
在Servlet中,HttpSession是一个接口,重要方法如下
String getId();
void setMaxInactiveInterval(int var1);
void invalidate();
ServletContext getServletContext();
void setAttribute(String var1, Object var2);
Object getAttribute(String var1);
void removeAttribute(String var1);
16.cookie机制
cookie是服务器让浏览器保存键值对的一种技术.浏览器有了cookie后,每一次请求(指定路径下的请求)都会发送给服务器,特别是session机制是通过cookie技术来实现的,服务器第一次根据新的请求创建好session后,会生成sessionId和session对象,sessionId会响应给浏览器,怎么响应呢?服务器自动创建一个cookie对象,这个cookie 的key就是JSESSIONID,value就是类似9484927F75F2A4这种,浏览器获取到这个cookie后会自动在内存中保存这个键值对.
在java中Cookie是一个类,实现了Cloneable,Serializable接口.阅读源码,类似一个javabean对象,重要属性有name,value,maxAge,path,均进行了封装,有这些属性的set和get方法,cookie存在的形式是key,value. key是name属性,有value属性.
maxAge指明了cookie存活时间和存活地方.maxAge>0:表示指定秒数后过期,maxAge<0,浏览器关闭,cookie就删除(默认为-1),maxAge=0,表示马上删除cookie
Path:表示那些请求地址后Cookie会发送给服务器,哪些请求地址不发cookie给服务器.path=/oa/abc 表示/oa/abc/*路径会发送cookie
若是没有指定Path,则默认会只要是项目下的请求.浏览器都会携带Cookie传到服务器中
17.过滤器
JavaWeb中有个接口为Filter,称为过滤器,过滤器可以实现在执行Servlet之前,执行一些通用的业务逻辑,比如统一处理乱码问题,统一检查用户是否处于登录状态等等.
编写过滤器分为以下两步
- 编写一个类,实现Filter接口,并实现Filter中doFilter(ServletRequest req,ServletResponse resp)方法,方法中通过filterChain(req,resp)放行代码到下一个Filter
- 在web.xml中的Filter标签进行name,class和url的配置,或者通过@WebFilter({“/oa”})注解配置
Filter天生优先级比Servlet高,同样的路径,先执行Filter,过滤器放行后执行Servlet
Filter默认在服务器启动时自动创建对象,创建对象时在构造方法中会执行init方法,init方法中有filterConfig对象.这个对象封装了web.xml中Filter标签信息
Filter执行代码的顺序是: 过滤器1放行前置代码–>过滤器2放行前置代码->过滤器3放行前置代码…->目标代码->过滤器3放行后置代码->过滤器2放行后置代码->过滤器1放行后置代码
//Filter接口已经实现了init和destroy方法,我们只需重写doFilter方法
public interface Filter {
default void init(FilterConfig filterConfig) throws ServletException {
}
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
default void destroy() {
}
}
18.监视器
JavaWeb有三大组件: Servlet Filter Listeren
什么是监听器
监听器是Servlet规范中的一员,是JavaWeb三大组件之一,在servlet中所有的监听器都以Listeren结尾,都是接口
作用:sum公司给程序员提供的各种各样的特殊时刻,以便我们可以在某些特殊时刻想执行一段代码时有地方放
这个特殊时刻比如:在ServletContext对象创建好的那一刻(服务器刚启动后的那个时间点),Session对象创建好的那一刻,Session域放入了User对象后这个时刻点,等等
Servlet规范中提供了以下监听器
//jakarta.servlet包下
ServletContextListener
ServletContextAttributeListener
ServletRequestListener
ServletRequestAttributeListener
//jakarta.servlet.http包下
HttpSessionListener
HttpSessionAttributeListener
HttpSessionBindingListener
HttpSessionIdListener
HttpSessionActivationListener
实现一个监听器的步骤
- 编写一个类实现以上监听器接口,实现接口里面的方法
- 在web.xml中编写listener标签,或者类上使用@WebFilter注解
评论区